var isFinish = false;

var game = new function() {
    var self = this;

    var isFinish = false;

    self.init = function(){
        initKeyboardListener();
        initWorld();
        initSnake();
    };

    self.start = function(){};
    self.stop = function(){};

    self.update = function() {
        if (isFinish) return;
        world.update();

        if (!food.isExist) {
            generateFood();
        }

        step();
    };

    self.isFinish = function(){
        return isFinish;
    };
};

var world;
function World(canvas) {
    var self = this;
    var snake = new Snake();
    var food = new Food();

    (function() {
        self.minX = 0;
        self.minY = 0;

        self.maxX = canvas.width/25 - 1;
        self.maxY = canvas.height/25 - 1;
    })();

    self.update = function() {
        if (!food.isExist) {

        }
    };

    self.step = function(){};
};

var snake = new Snake();
function Snake() {
    var self = this;

    self.body = [];
    self.moveDirection = {};

    (function(){
        self.body.push({x:6, y:3});
        self.body.push({x:5, y:3});
        self.body.push({x:4, y:3});

        self.moveDirection = {x:1, y:0};
    })();

    (function() {
        $(document).bind('arrow_left',  function(){self.moveDirection = {x:-1,  y:0};});
        $(document).bind('arrow_up',    function(){self.moveDirection = {x:0,   y:-1};});
        $(document).bind('arrow_right', function(){self.moveDirection = {x:1,   y:0};});
        $(document).bind('arrow_down',  function(){self.moveDirection = {x:0,   y:1};});
    })();
};

var food;
function Food() {
    var self = this;

    self.position = {};
};

function onLoad() {
    initGame();
    startGame();
}

function initGame() {
    //initKeyboardListener();
    world = new World(document.getElementById("snake"));
}

function startGame() {
    game.update = setInterval(update, 150);
    game.display = setInterval(display, 20);
}

function generateFood() {
    food = new Food();

    food.position.x = Math.floor(Math.random()*world.maxX + 0.5);
    food.position.y = Math.floor(Math.random()*world.maxY + 0.5);

    if (!isCellEmpty(food.position.x, food.position.y)) {
        generateFood();
    }
}

function isCellEmpty(x, y) {
    for (var i=0;i<snake.body.length;i++) {
        if (snake.body[i].x == x && snake.body[i].y == y) return false;
    }

    return true;
}

function update() {
    if (isFinish) return;
    if (!food) generateFood();
    step();
}

function display() {
    clearCanvas();
    if(food) drawFood();
    drawSnake();
}

function drawFood() {
    drawCell(food.position.x, food.position.y);
}

function clearCanvas() {
    var canvas = document.getElementById("snake");
    var ctx = canvas.getContext("2d");

    ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function drawSnake() {
    for (var i=0;i<snake.body.length;i++) {
        drawCell(snake.body[i].x, snake.body[i].y);
    }
}

function drawCell(x, y) {
    var canvas = document.getElementById("snake");
    var ctx = canvas.getContext("2d");

    ctx.fillRect(25*x + 1, 25*y + 1, 23, 23);
}

function step() {
    var head = {
        x: snake.body[0].x + snake.moveDirection.x,
        y: snake.body[0].y + snake.moveDirection.y
    };

    if (head.x == food.position.x && head.y == food.position.y) {
        snake.body.unshift(head);
        food = undefined;
        return;
    }

    if (!isCellEmpty(head.x, head.y) && !(
        head.x == snake.body[snake.body.length-1].x &&
        head.y == snake.body[snake.body.length-1].y)) {
        isFinish = true;
        return;
    }

    if (head.x<world.minX || head.x>world.maxX) head.x -= snake.moveDirection.x;
    if (head.y<world.minY || head.y>world.maxY) head.y -= snake.moveDirection.y;

    if ((head.x == snake.body[0].x) && (head.y == snake.body[0].y)) {
        isFinish = true;
    } else {
        snake.body.unshift(head);
        snake.body.pop();
    }
}
